﻿using JNPF.Basics.Models;
using JNPF.Utils;
using Senparc.Weixin;
using Senparc.Weixin.MP;
using Senparc.Weixin.MP.AdvancedAPIs;
using Senparc.Weixin.MP.AdvancedAPIs.GroupMessage;
using Senparc.Weixin.MP.AdvancedAPIs.User;
using Senparc.Weixin.MP.CommonAPIs;
using Senparc.Weixin.MP.Containers;
using Senparc.Weixin.MP.Entities.Menu;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Text;

namespace JNPF.Basics.Logic
{
    /// <summary>
    /// 公众号处理工厂
    /// </summary>
    public class WeChatMPHelper
    {
        public string accessToken { get; set; }
        /// <summary>
        /// 构造函数(无参)
        /// </summary>
        public WeChatMPHelper() { }
        /// <summary>
        /// 构造函数(带参)
        /// </summary>
        /// <param name="appId"></param>
        /// <param name="appSecret"></param>
        public WeChatMPHelper(string appId, string appSecret)
        {
            try
            {
                accessToken = AccessTokenContainer.TryGetAccessToken(appId, appSecret);
            }
            catch (Exception e)
            {

                throw new Exception(e.Message);
            }
        }

        #region 微信后台验证地址/处理用户发送消息后
        /// <summary>
        /// 微信后台验证地址
        /// </summary>
        /// <param name="signature">签名</param>
        /// <param name="timestamp">时间戳</param>
        /// <param name="nonce">nonce</param>
        /// <param name="echostr">算出的值</param>
        /// <returns></returns>
        public HttpResponseMessage GetCheckToken(string signature, string timestamp, string nonce, string echostr)
        {
            var token = "WEIXINJNPF";
            if (CheckSignature.Check(signature, timestamp, nonce, token))
            {
                var result = new StringContent(echostr, UTF8Encoding.UTF8, "application/x-www-form-urlencoded");
                var response = new HttpResponseMessage { Content = result };
                return response;
            }
            else
            {
                var result = new StringContent("failed:" + signature + "," + CheckSignature.GetSignature(timestamp, nonce, token) + "。" +
                     "如果你在浏览器中看到这句话，说明此地址可以被作为微信公众账号后台的Url，请注意保持Token一致。", UTF8Encoding.UTF8, "application/x-www-form-urlencoded");
                var response = new HttpResponseMessage(HttpStatusCode.BadRequest);
                response.Content = result;
                return response;
            }
        }
        /// <summary>
        /// 处理用户发送消息后
        /// </summary>
        /// <returns></returns>
        public HttpResponseMessage ReceiveMessage()
        {
            var httpContext = Utils.HttpContext.Current;
            int maxRecordCount = 10000;
            var stream = Utils.HttpContext.Current.Request.Body;
            var messageHandler = new CustomMessageHandler(stream, null, maxRecordCount);
            messageHandler.Execute();
            if (messageHandler.ResponseDocument != null)
            {
                return new HttpResponseMessage { Content = new StringContent(messageHandler.ResponseDocument.ToString(), Encoding.GetEncoding("UTF-8"), "text/plain") };
            }
            else
            {
                return new HttpResponseMessage { Content = new StringContent("", Encoding.GetEncoding("UTF-8"), "text/plain") };
            }
        }
        #endregion

        #region 菜单管理
        /// <summary>
        /// 删除自定义菜单
        /// </summary>
        /// <returns></returns>
        public bool DeleteMenu()
        {
            var result = CommonApi.DeleteMenu(accessToken);
            if (result.errcode == 0)
            {
                return true;
            }
            else
            {
                throw new Exception(result.errmsg);
            }
        }
        /// <summary>
        /// 创建自定义菜单
        /// </summary>
        /// <param name="menuJson">菜单Json</param>
        /// <returns></returns>
        public string CreateMenu(string menuJson)
        {
            ButtonGroup bg = new ButtonGroup();
            var menuButtonList = menuJson.ToList<MPMenuButtonModel>();
            foreach (var item in menuButtonList)
            {
                if (item.type == "view")
                {
                    bg.button.Add(new SingleViewButton() { url = item.url, name = item.name });
                }
                else if (item.type == "click")
                {
                    bg.button.Add(new SingleClickButton() { name = item.name, key = item.key });
                }
                else
                {
                    if (item.sub_button.Count == 0)
                    {
                        bg.button.Add(new SingleClickButton() { name = item.name, key = item.key });
                    }
                    else
                    {
                        var subButton = new SubButton()
                        {
                            name = item.name
                        };
                        foreach (var subItem in item.sub_button)
                        {
                            if (subItem.type == "view")
                            {
                                subButton.sub_button.Add(new SingleViewButton() { url = subItem.url, name = subItem.name });
                            }
                            else if (subItem.type == "click")
                            {
                                subButton.sub_button.Add(new SingleClickButton() { key = subItem.key, name = subItem.name });
                            }
                        }
                        bg.button.Add(subButton);
                    }
                }
            };
            var result = CommonApi.CreateMenu(accessToken, bg);
            Dictionary<string, object> dic = new Dictionary<string, object>();
            dic.Add("errcode", result.errcode);
            dic.Add("errmsg", result.errmsg);
            return dic.ToJson();
        }
        /// <summary>
        /// 查询自定义菜单
        /// </summary>
        /// <returns></returns>
        public string GetMenu()
        {

            try
            {
                var result = CommonApi.GetMenu(accessToken);
                if (result.errcode == 0)
                {
                    return result.menu.button.ToJson();
                }
                else
                {
                    throw new Exception(result.errmsg);
                }
            }
            catch (Exception)
            {
                return "";
            }
        }
        #endregion

        #region 用户管理
        /// <summary>
        /// 获取OpenId信息
        /// </summary>
        /// <returns></returns>
        public string GetUserList()
        {
            var nextOpenid = "";
            var result = UserApi.Get(accessToken, nextOpenid);
            if (result.errcode == 0)
            {
                Dictionary<string, object> dic = new Dictionary<string, object>();
                dic.Add("openid", result.data == null ? null : result.data.openid);
                dic.Add("next_openid", result.next_openid);
                dic.Add("total", result.total);
                dic.Add("count", result.count);
                return dic.ToJson();
            }
            else
            {
                throw new Exception(result.errmsg);
            }
        }
        /// <summary>
        /// 获取黑名单
        /// </summary>
        /// <returns></returns>
        public string GetBlackList()
        {
            var beginOpenId = "";
            var result = UserApi.GetBlackList(accessToken, beginOpenId);
            if (result.errcode == 0)
            {
                Dictionary<string, object> dic = new Dictionary<string, object>();
                dic.Add("openid", result.data == null ? null : result.data.openid);
                dic.Add("next_openid", result.next_openid);
                dic.Add("total", result.total);
                dic.Add("count", result.count);
                return dic.ToJson();
            }
            else
            {
                throw new Exception(result.errmsg);
            }
        }
        /// <summary>
        /// 拉黑用户
        /// </summary>
        /// <param name="openIdList"></param>
        /// <returns></returns>
        public bool BatchBlackList(List<string> openIdList)
        {
            var result = UserApi.BatchBlackList(accessToken, openIdList);
            if (result.errcode == 0)
            {
                return true;
            }
            else
            {
                throw new Exception(result.errmsg);
            }
        }
        /// <summary>
        /// 取消拉黑用户
        /// </summary>
        /// <param name="openIdList">openId用户列表</param>
        /// <returns></returns>
        public bool BatchUnBlackList(List<string> openIdList)
        {
            var result = UserApi.BatchUnBlackList(accessToken, openIdList);
            if (result.errcode == 0)
            {
                return true;
            }
            else
            {
                throw new Exception(result.errmsg);
            }
        }
        /// <summary>
        /// 获取用户信息
        /// </summary>
        /// <param name="openId">普通用户的标识</param>
        /// <returns></returns>
        public MPUserModel UserInfo(string openId)
        {
            MPUserModel userModel = new MPUserModel();
            var userInfo = UserApi.Info(accessToken, openId);
            userModel.nickname = userInfo.nickname;
            userModel.subscribe_scene = userInfo.subscribe_scene;
            userModel.tagid_list = userInfo.tagid_list;
            userModel.groupid = userInfo.groupid;
            userModel.remark = userInfo.remark;
            userModel.unionid = userInfo.unionid;
            userModel.subscribe_time = userInfo.subscribe_time;
            userModel.headimgurl = userInfo.headimgurl;
            userModel.country = userInfo.country;
            userModel.province = userInfo.province;
            userModel.city = userInfo.city;
            userModel.language = userInfo.language;
            userModel.sex = userInfo.sex;
            userModel.openid = userInfo.openid;
            userModel.subscribe = userInfo.subscribe;
            userModel.qr_scene = userInfo.qr_scene;
            userModel.qr_scene_str = userInfo.qr_scene_str;
            return userModel;
        }
        /// <summary>
        /// 批量获取用户基本信息
        /// </summary>
        /// <param name="openIdList">openId用户列表</param>
        /// <returns></returns>
        public string BatchGetUserInfo(List<string> openIdList)
        {
            List<BatchGetUserInfoData> userInfoList = new List<BatchGetUserInfoData>();
            foreach (var openid in openIdList)
            {
                userInfoList.Add(new BatchGetUserInfoData
                {
                    openid = openid,
                    LangEnum = Language.zh_CN,
                    lang = "zh_CN",
                });
            }
            var result = UserApi.BatchGetUserInfo(accessToken, userInfoList);
            if (result.errcode == 0)
            {
                return result.user_info_list.ToJson();
            }
            else
            {
                throw new Exception(result.errmsg);
            }
        }
        /// <summary>
        /// 修改关注者备注信息
        /// </summary>
        /// <param name="openId">普通用户的标识</param>
        /// <param name="remark">新的备注名</param>
        /// <returns></returns>
        public bool UpdateRemark(string openId, string remark)
        {
            var result = UserApi.UpdateRemark(accessToken, openId, remark);
            if (result.errcode == 0)
            {
                return true;
            }
            else
            {
                throw new Exception(result.errmsg);
            }
        }
        #endregion

        #region 标签管理
        /// <summary>
        /// 获取用户身上的标签列表
        /// </summary>
        /// <param name="OpenId">普通用户的标识</param>
        /// <returns></returns>
        public bool GetUserTagList(string OpenId)
        {
            var result = UserTagApi.UserTagList(accessToken, OpenId);
            if (result.errcode == 0)
            {
                return true;
            }
            else
            {
                throw new Exception(result.errmsg);
            }
        }
        /// <summary>
        /// 获取公众号已创建的标签
        /// </summary>
        /// <returns></returns>
        public List<MPTagsModel> GetTagsList()
        {
            var result = UserTagApi.Get(accessToken);
            if (result.errcode == 0)
            {
                List<MPTagsModel> tagsModelList = new List<MPTagsModel>();
                foreach (var tag in result.tags)
                {
                    tagsModelList.Add(new MPTagsModel
                    {
                        id = tag.id,
                        name = tag.name,
                        count = tag.count
                    });
                }
                return tagsModelList;
            }
            else
            {
                throw new Exception(result.errmsg);
            }
        }
        /// <summary>
        /// 获取标签下粉丝列表
        /// </summary>
        /// <param name="tagid">标签Id</param>
        /// <param name="nextOpenid"></param>
        /// <returns></returns>
        public string GetTagUsers(int tagid, string nextOpenid)
        {
            var result = UserTagApi.Get(accessToken, tagid, nextOpenid);
            if (result.errcode == 0)
            {
                Dictionary<string, object> dic = new Dictionary<string, object>();
                dic.Add("openid", result.data == null ? null : result.data.openid);
                dic.Add("next_openid", result.next_openid);
                dic.Add("count", result.count);
                return dic.ToJson();
            }
            else
            {
                throw new Exception(result.errmsg);
            }
        }
        /// <summary>
        /// 创建标签
        /// </summary>
        /// <param name="tagName">标签名</param>
        /// <returns></returns>
        public string CreateTag(string tagName)
        {
            var result = UserTagApi.Create(accessToken, tagName);
            if (result.errcode == 0)
            {
                return result.tag.ToJson();
            }
            else
            {
                throw new Exception(result.errmsg);
            }
        }
        /// <summary>
        /// 删除标签
        /// </summary>
        /// <param name="id">标签Id</param>
        /// <returns></returns>
        public bool DeleteTag(int id)
        {
            var result = UserTagApi.Delete(accessToken, id);
            if (result.errcode == 0)
            {
                return true;
            }
            else
            {
                throw new Exception(result.errmsg);
            }
        }
        /// <summary>
        /// 编辑标签
        /// </summary>
        /// <param name="id">Id</param>
        /// <param name="tagName">标签名</param>
        /// <returns></returns>
        public bool UpdateTag(int id, string tagName)
        {
            var result = UserTagApi.Update(accessToken, id, tagName);
            if (result.errcode == 0)
            {
                return true;
            }
            else
            {
                throw new Exception(result.errmsg);
            }
        }
        /// <summary>
        /// 批量为用户打标签
        /// </summary>
        /// <param name="tagid">标签Id</param>
        /// <param name="openid_list">OpenId列表</param>
        /// <returns></returns>
        public bool BatchTagged(int tagid, List<string> openid_list)
        {
            var result = UserTagApi.BatchTagging(accessToken, tagid, openid_list);
            if (result.errcode == 0)
            {
                return true;
            }
            else
            {
                throw new Exception(result.errmsg);
            }
        }
        /// <summary>
        /// 批量为用户取消标签
        /// </summary>
        /// <param name="tagid">标签编码</param>
        /// <param name="openid_list">OpenId集合</param>
        /// <returns></returns>
        public bool BatchUnTagged(int tagid, List<string> openid_list)
        {
            var result = UserTagApi.BatchUntagging(accessToken, tagid, openid_list);
            if (result.errcode == 0)
            {
                return true;
            }
            else
            {
                throw new Exception(result.errmsg);
            }
        }
        #endregion

        #region 素材管理
        #region Get
        /// <summary>
        /// 获取临时素材
        /// </summary>
        /// <param name="mediaId"> 要获取的素材的media_id</param>
        /// <param name="stream"> 写入文件流</param>
        public void Get(string mediaId, Stream stream)
        {
            MediaApi.Get(accessToken, mediaId, stream);
        }
        /// <summary>
        /// 获取临时素材并保存
        /// </summary>
        /// <param name="mediaId"> 要获取的素材的media_id</param>
        /// <param name="dir">储存目录</param>
        public string GetDir(string mediaId, string dir)
        {
            var result = MediaApi.Get(accessToken, mediaId, dir);
            return result.ToJson();
        }
        /// <summary>
        /// 获取永久素材(除了图文、视频)
        /// </summary>
        /// <param name="mediaId"> 要获取的素材的media_id</param>
        /// <param name="stream"> 写入文件流</param>
        /// <returns></returns>
        public bool GetForeverMedia(string mediaId, Stream stream)
        {
            var result = MediaApi.GetForeverMedia(accessToken, mediaId, stream);
            if (result.errcode == 0)
            {
                return true;
            }
            else
            {
                throw new Exception(result.errmsg);
            }
        }

        /// <summary>
        /// 获取永久图文素材
        /// </summary>
        /// <param name="mediaId"> 要获取的素材的media_id</param>
        /// <param name="mediaId"></param>
        /// <returns></returns>
        public bool GetForeverNews(string mediaId)
        {
            var result = MediaApi.GetForeverNews(accessToken, mediaId);
            if (result.errcode == 0)
            {
                return true;
            }
            else
            {
                throw new Exception(result.errmsg);
            }
        }
        /// <summary>
        /// 获取永久视频素材
        /// </summary>
        /// <param name="mediaId"> 要获取的素材的media_id</param>
        /// <returns></returns>
        public bool GetForeverVideo(string mediaId)
        {
            var result = MediaApi.GetForeverVideo(accessToken, mediaId);
            if (result.errcode == 0)
            {
                return true;
            }
            else
            {
                throw new Exception(result.errmsg);
            }
        }
        /// <summary>
        /// 获取素材总数
        /// </summary>
        /// <returns></returns>
        public bool GetMediaCount()
        {
            var result = MediaApi.GetMediaCount(accessToken);
            if (result.errcode == 0)
            {
                return true;
            }
            else
            {
                throw new Exception(result.errmsg);
            }
        }
        /// <summary>
        /// 获取图文素材列表
        /// </summary>
        /// <param name="accessToken"></param>
        /// <param name="offset"> 从全部素材的该偏移位置开始返回，0表示从第一个素材 返回</param>
        /// <param name="count">返回素材的数量，取值在1到20之间</param>
        /// <returns></returns>
        public bool GetNewsMediaList(string accessToken, int offset, int count)
        {
            var result = MediaApi.GetNewsMediaList(accessToken, offset, count);
            if (result.errcode == 0)
            {
                return true;
            }
            else
            {
                throw new Exception(result.errmsg);
            }
        }
        /// <summary>
        /// 获取图片、视频、语音素材列表
        /// </summary>
        /// <param name="type"> 素材的类型</param>
        /// <param name="offset"> 从全部素材的该偏移位置开始返回，0表示从第一个素材 返回</param>
        /// <param name="count">返回素材的数量，取值在1到20之间</param>
        /// <returns></returns>
        public string GetOthersMediaList(int type, int offset = 0, int count = 20)
        {
            UploadMediaFileType fileType = new UploadMediaFileType();
            switch (type)
            {
                case 1:
                    fileType = UploadMediaFileType.image;
                    break;
                case 2:
                    fileType = UploadMediaFileType.voice;
                    break;
                case 3:
                    fileType = UploadMediaFileType.video;
                    break;
                case 4:
                    fileType = UploadMediaFileType.news;
                    break;
                case 5:
                    fileType = UploadMediaFileType.thumb;
                    break;
                default:
                    break;
            }
            var result = MediaApi.GetOthersMediaList(accessToken, fileType, offset, count);
            if (result.errcode == 0)
            {
                Dictionary<string, object> dic = new Dictionary<string, object>();
                dic.Add("item", result.item == null ? null : result.item);
                dic.Add("total", result.total_count);
                dic.Add("count", result.item_count);
                return dic.ToJson();
            }
            else
            {
                throw new Exception(result.errmsg);
            }
        }
        #endregion

        #region Post
        /// <summary>
        /// 删除永久素材
        /// </summary>
        /// <param name="mediaId">永久素材主键</param>
        /// <returns></returns>
        public bool DeleteForeverMedia(string mediaId)
        {
            var result = MediaApi.DeleteForeverMedia(accessToken, mediaId);
            if (result.errcode == 0)
            {
                return true;
            }
            else
            {
                throw new Exception(result.errmsg);
            }
        }
        /// <summary>
        /// 修改永久图文素材
        /// </summary>
        /// <param name="mediaId">永久图文素材主键</param>
        /// <param name="index">下标</param>
        /// <param name="news">对象实体</param>
        /// <returns></returns>
        public bool UpdateForeverNews(string mediaId, int index, MPMaterialModel materialModel)
        {
            NewsModel news = new NewsModel();
            news.author = materialModel.author;
            news.content = materialModel.content;
            news.content_source_url = materialModel.content_source_url;
            news.digest = materialModel.digest;
            news.need_open_comment = materialModel.need_open_comment;
            news.only_fans_can_comment = materialModel.only_fans_can_comment;
            news.show_cover_pic = materialModel.show_cover_pic;
            news.thumb_media_id = materialModel.thumb_media_id;
            news.thumb_url = materialModel.thumb_url;
            news.title = materialModel.title;
            var result = MediaApi.UpdateForeverNews(accessToken, mediaId, index, news);
            if (result.errcode == 0)
            {
                return true;
            }
            else
            {
                throw new Exception(result.errmsg);
            }
        }
        /// <summary>
        ///  新增其他类型永久素材(图片（image）、语音（voice）和缩略图（thumb）)
        /// </summary>
        /// <param name="accessToken"></param>
        /// <param name="fille"></param>
        /// <returns></returns>
        public string UploadForeverMedia(string file)
        {
            var result = MediaApi.UploadForeverMedia(accessToken, file);
            if (result.errcode == 0)
            {
                Dictionary<string, object> dic = new Dictionary<string, object>();
                dic.Add("errcode", result.errcode);
                dic.Add("errmsg", result.errmsg);
                dic.Add("mediaid", result.media_id);
                dic.Add("url", result.url);
                return dic.ToJson();
            }
            else
            {
                throw new Exception(result.errmsg);
            }
        }
        /// <summary>
        ///  新增永久视频素材
        /// </summary>
        /// <param name="file">上传文件的绝对路径</param>
        /// <param name="title">素材标题</param>
        /// <param name="introduction">视频描述</param>
        /// <returns></returns>
        public string UploadForeverVideo(string file, string title, string introduction)
        {
            var result = MediaApi.UploadForeverVideo(accessToken, file, title, introduction, "video");
            if (result.errcode == 0)
            {
                Dictionary<string, object> dic = new Dictionary<string, object>();
                dic.Add("errcode", result.errcode);
                dic.Add("errmsg", result.errmsg);
                dic.Add("mediaid", result.media_id);
                dic.Add("url", result.url);
                return dic.ToJson();
            }
            else
            {
                throw new Exception(result.errmsg);
            }
        }
        /// <summary>
        /// 上传图文消息内的图片
        /// </summary>
        /// <param name="file">上传文件的绝对路径</param>
        /// <returns></returns>
        public string UploadImg(string file)
        {
            var result = MediaApi.UploadImg(accessToken, file);
            if (result.errcode == 0)
            {
                return result.url;
            }
            else
            {
                throw new Exception(result.errmsg);
            }
        }
        /// <summary>
        /// 新增永久图文素材
        /// </summary>
        /// <param name="news">>图文消息组</param>
        /// <param name="timeOut"></param> 
        /// <returns></returns>
        public string UploadNews(MPMaterialModel materialModel, int timeOut = 10000)
        {
            List<NewsModel> news = new List<NewsModel>();
            news.Add(new NewsModel
            {
                title = materialModel.title,
                author = materialModel.author,
                content = materialModel.content,
                content_source_url = materialModel.content_source_url,
                digest = materialModel.digest,
                need_open_comment = materialModel.need_open_comment,
                only_fans_can_comment = materialModel.only_fans_can_comment,
                show_cover_pic = materialModel.show_cover_pic,
                thumb_media_id = materialModel.thumb_media_id,
                thumb_url = materialModel.thumb_url
            });
            var result = MediaApi.UploadNews(accessToken, timeOut, news.ToArray());
            if (result.errcode == 0)
            {
                Dictionary<string, object> dic = new Dictionary<string, object>();
                dic.Add("errcode", result.errcode);
                dic.Add("errmsg", result.errmsg);
                dic.Add("mediaid", result.media_id);
                dic.Add("url", result.url);
                return dic.ToJson();
            }
            else
            {
                throw new Exception(result.errmsg);
            }
        }
        /// <summary>
        /// 新增临时素材
        /// </summary>
        /// <param name="type"> 媒体文件类型</param>
        /// <param name="file">上传文件的绝对路径</param>
        /// <returns></returns>
        public bool UploadTemporaryMedia(int type, string file)
        {
            UploadMediaFileType fileType = new UploadMediaFileType();
            switch (type)
            {
                case 2://图片 
                    fileType = UploadMediaFileType.image;
                    break;
                case 3://语音
                    fileType = UploadMediaFileType.voice;
                    break;
                case 4://视频
                    fileType = UploadMediaFileType.video;
                    break;
                case 5:// thumb：64KB，支持JPG格式
                    fileType = UploadMediaFileType.thumb;
                    break;
                case 6://图文
                    fileType = UploadMediaFileType.news;
                    break;
                default:
                    break;
            }
            var result = MediaApi.UploadTemporaryMedia(accessToken, fileType, file);
            if (result.errcode == 0)
            {
                return true;
            }
            else
            {
                throw new Exception(result.errmsg);
            }
        }
        /// <summary>
        /// 上传临时图文素材
        /// </summary>
        /// <param name="news">图文消息组</param>
        /// <returns></returns>
        public bool UploadTemporaryNews(NewsModel news)
        {
            var result = MediaApi.UploadTemporaryNews(accessToken, news.ToInt());
            if (result.errcode == 0)
            {
                return true;
            }
            else
            {
                throw new Exception(result.errmsg);
            }
        }
        #endregion
        #endregion

        #region 消息发送
        /// <summary>
        /// 删除群发消息
        /// </summary>
        /// <param name="msgId"> 发送出去的消息ID</param>
        /// <param name="articleIdx">要删除的文章在图文消息中的位置</param>
        /// <returns></returns>
        public bool DeleteSendMessage(string msgId, int articleIdx)
        {
            var result = GroupMessageApi.DeleteSendMessage(accessToken, msgId, articleIdx);
            if (result.errcode == 0)
            {
                return true;
            }
            else
            {
                throw new Exception(result.errmsg);
            }
        }
        /// <summary>
        ///  查询群发消息发送状态
        /// </summary>
        /// <param name="msgId">群发消息后返回的消息id</param>
        /// <returns></returns>
        public bool GetGroupMessageResult(string msgId)
        {
            var result = GroupMessageApi.GetGroupMessageResult(accessToken, msgId);
            if (result.errcode == 0)
            {
                return true;
            }
            else
            {
                throw new Exception(result.errmsg);
            }
        }
        /// <summary>
        /// 获取视频群发用的MediaId
        /// </summary>
        /// <param name="mediaId">用于群发的消息的media_id</param>
        /// <param name="title">消息的标题</param>
        /// <param name="description">消息的描述</param>
        /// <returns></returns>
        public bool GetVideoMediaIdResult(string mediaId, string title, string description)
        {
            var result = GroupMessageApi.GetVideoMediaIdResult(accessToken, title, description, mediaId);
            if (result.errcode == 0)
            {
                return true;
            }
            else
            {
                throw new Exception(result.errmsg);
            }
        }
        /// <summary>
        /// 根据OpenID列表群发视频消息
        /// </summary>
        /// <param name="mediaId">用于群发的消息的media_id</param>
        /// <param name="title">消息的标题</param>
        /// <param name="description">消息的描述</param>
        /// <param name="openIds">openId字符串数组</param>
        /// <returns></returns>
        public bool SendVideoGroupMessageByOpenId(string title, string description, string mediaId, string[] openIds)
        {
            var result = GroupMessageApi.SendVideoGroupMessageByOpenId(accessToken, title, description, mediaId, openIds.ToString());
            if (result.errcode == 0)
            {
                return true;
            }
            else
            {
                throw new Exception(result.errmsg);
            }
        }
        /// <summary>
        /// 预览接口【订阅号与服务号认证后均可用】
        /// </summary>
        /// <param name="type"></param>
        /// <param name="value">群发媒体消息时为media_id，群发文本信息为content</param>
        /// <param name="openId">公众号Id</param>
        /// <param name="wxName"> 接收消息用户的微信号</param>
        /// <returns></returns>
        public bool SendGroupMessagePreview(int? type, string value, string openId, string wxName = null)
        {
            GroupMessageType messageType = new GroupMessageType();
            switch (type)
            {
                case 1://文本
                    messageType = GroupMessageType.text;
                    break;
                case 2://图片
                    messageType = GroupMessageType.image;
                    break;
                case 3://语音
                    messageType = GroupMessageType.voice;
                    break;
                case 4://视频
                    messageType = GroupMessageType.video;
                    break;
                case 5://图文
                    messageType = GroupMessageType.mpnews;
                    break;
                case 6:// 卡券
                    messageType = GroupMessageType.wxcard;
                    break;
                default:
                    break;
            }
            var result = GroupMessageApi.SendGroupMessagePreview(accessToken, messageType, value, openId, wxName);
            if (result.errcode == 0)
            {
                return true;
            }
            else
            {
                throw new Exception(result.errmsg);
            };
        }
        /// <summary>
        /// 根据标签进行群发
        /// </summary>
        /// <param name="tagId">标签主键</param>
        /// <param name="value"> 群发媒体文件时传入mediaId,群发文本消息时传入content,群发卡券时传入cardId</param>
        /// <param name="type"></param>
        /// <param name="isToAll">是否向全部用户发送</param>
        /// <param name="sendIgnoreReprint">转载时是否群发</param>
        /// <param name="clientmsgid">开发者侧群发msgid</param>
        /// <returns></returns>
        public string SendGroupMessageByTagId(string tagId, string value, int? type, bool isToAll, bool sendIgnoreReprint = false, string clientmsgid = null)
        {
            try
            {
                GroupMessageType messageType = new GroupMessageType();
                switch (type)
                {
                    case 1://文本
                        messageType = GroupMessageType.text;
                        break;
                    case 2://图片
                        messageType = GroupMessageType.image;
                        break;
                    case 3://语音
                        messageType = GroupMessageType.voice;
                        break;
                    case 4://视频
                        messageType = GroupMessageType.video;
                        break;
                    case 5://图文
                        messageType = GroupMessageType.mpnews;
                        break;
                    case 6:// 卡券
                        messageType = GroupMessageType.wxcard;
                        break;
                    default:
                        break;
                }
                var result = GroupMessageApi.SendGroupMessageByTagId(accessToken, tagId, value, messageType, isToAll, sendIgnoreReprint, clientmsgid);
                if (result.errcode == 0)
                {
                    Dictionary<string, object> dic = new Dictionary<string, object>();
                    dic.Add("msgid", result.msg_id);
                    dic.Add("msgdataid", result.msg_data_id);
                    return dic.ToJson();
                }
                else
                {
                    throw new Exception(result.errmsg);
                }
            }
            catch (Exception ex)
            {

                throw new Exception(ex.Message); ;
            }
        }
        /// <summary>
        ///  根据OpenId进行群发
        /// </summary>
        /// <param name="type">消息类型</param>
        /// <param name="value">群发媒体文件时传入mediaId,群发文本消息时传入content,群发卡券时传入cardId</param>
        /// <param name="clientmsgid">开发者侧群发msgid，长度限制64字节，如不填，则后台默认以群发范围和群发内容的摘要值做为clientmsgid</param>
        /// <param name="openIds"> openId字符串数组</param>
        /// <param name="timeOut">代理请求超时时间（毫秒）</param>
        /// <returns></returns>
        public string SendGroupMessageByOpenId(int type, string value, string[] openIds, string clientmsgid = null, int timeOut = 10000)
        {
            GroupMessageType messageType = new GroupMessageType();
            switch (type)
            {
                case 1://文本
                    messageType = GroupMessageType.text;
                    break;
                case 2://图片
                    messageType = GroupMessageType.image;
                    break;
                case 3://语音
                    messageType = GroupMessageType.voice;
                    break;
                case 4://视频
                    messageType = GroupMessageType.video;
                    break;
                case 5://图文
                    messageType = GroupMessageType.mpnews;
                    break;
                case 6:// 卡券
                    messageType = GroupMessageType.wxcard;
                    break;
                default:
                    break;
            }
            var result = GroupMessageApi.SendGroupMessageByOpenId(accessToken, messageType, value, clientmsgid, timeOut, openIds);
            if (result.errcode == 0)
            {
                Dictionary<string, object> dic = new Dictionary<string, object>();
                dic.Add("msgid", result.msg_id);
                dic.Add("msgdataid", result.msg_data_id);
                return dic.ToJson();
            }
            else
            {
                throw new Exception(result.errmsg);
            };
        }

        #endregion
    }
}
